﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Ace.Application;
using Microsoft.Extensions.Configuration;
using Ace;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.FileProviders;
using System.Reflection;
using System.IO;
using Microsoft.Extensions.DependencyModel;
using Ace.AutoMapper;
using System.Text;
using NLog.Extensions.Logging;
using NLog.Web;
using Ace.Web.Mvc;

namespace Chloe.Home
{
    /// <summary>
    /// c:\users\quzhl\documents\visual studio 2017\Projects
    /// 可以用来定义请求处理管道和配置应用需要的服务
    ///      Startup类必须是Public，且必须包含上面两个方法。ConfigureServices和Configure
    /// </summary>
    public class Startup
    {
        IHostingEnvironment _env;
        /// <summary>
        /// ①构造函数，加载配置
        /// </summary>
        /// <param name="env"></param>
        public Startup(IHostingEnvironment env)
        {
            this._env = env;

            var builder = new ConfigurationBuilder()
                      .SetBasePath(env.ContentRootPath)
                      .AddJsonFile(Path.Combine("configs", "appsettings.json"), optional: true, reloadOnChange: true)  // Settings for the application
                      .AddJsonFile(Path.Combine("configs", $"appsettings.{env.EnvironmentName}.json"), optional: true, reloadOnChange: true)
                      .AddEnvironmentVariables();                                              // override settings with environment variables set in compose.   

            //if (env.IsDevelopment())
            //{
            //    // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
            //    builder.AddUserSecrets();
            //}

            Configuration = builder.Build();
            Globals.Configuration = Configuration;
        }



        public IConfigurationRoot Configuration { get; }
        /// <summary>
        /// ② 注册服务   定义应用所使用的服务
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.RegisterAppServices(); /* 注册应用服务 */

            services.AddSession();
            services.AddResponseCaching(); //https://docs.microsoft.com/en-us/aspnet/core/performance/caching/response
            services.AddMvc(options =>
            {
                options.Filters.Add(typeof(HttpGlobalExceptionFilter));
            }).AddControllersAsServices();
        }

        /// <summary>
        /// ③ 定义请求管道中的中间件
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="loggerFactory"></param>
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            /* NLog */
            this._env.ConfigureNLog(Path.Combine("configs", "nlog.config"));
            loggerFactory.AddNLog();
            app.AddNLogWeb();

            Globals.ServiceProvider = app.ApplicationServices;
            AceMapper.InitializeMap(); /* 初始化 AutoMapper */

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
            //在非开发环境时，UseExceptionHandler时第一个被加入到请求管道的中间件。此后将会捕捉之后发生的任何异常，然后跳转到异常页（/Home/Error）。一般会把异常处理放在前面，这样可以捕捉后续调用中间件发生的异常。
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            //接下来是静态文件中间件，它将提供位于wwwroot下的文件的访问权限，并且是完全公开，如果想基于授权来提供这些文件，就不能放在wwwroot，而是放在之外的目录通过控制器判断授权，再由FileResult来提供文件
            // wwwroot是默认的Web根目录，用于存放类似于CSS、JS和图片文件的公开、静态的资源的目录。在Configure方法中使用静态文件中间件后，就可以读取wwwroot中的文件。Web根目录也可以通过WebHostBuilder来指定另外一个地址。
            app.UseStaticFiles(); //允许访问wwwroot文件夹下的静态文件

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme,
                AutomaticAuthenticate = true,
            });


            app.UseSession();
            app.UseResponseCaching();
            // 被静态文件处理的请求会在管道中短路。如果该请求不是由静态文件处理则会执行最后的MVC框架
            app.UseMvc(routes =>  // 设置MVC路由
            {
                routes.MapRoute(
                    name: "area",
                    template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");

                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}
